﻿#region Usings

extern alias RoutineBase1000;
extern alias RoutineBase1100;
extern alias RoutineBase1120;

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.Objects;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using Citi.Helpers;
using Citi.Scheduler.Domain;
using Citi.Scheduler.Domain.Utils;
using Citi.Scheduler.WindowsServices.EmailSenderWcf;
using Citi.SecurityHelper;
using Timer = System.Timers.Timer;

#endregion

namespace Citi.Scheduler.WindowsServices
{
    public static class ExecutionAction
    {
        #region Properties

        private static Timer timerMemory = new Timer { Interval = TimeLogMemory };

        private static CurrentAction CurrentAction { get; set; }
        private static CurrentAction1120 CurrentAction1120 { get; set; }
        private static RoutineExecutionStatus currentStatus;

        public static RoutineExecutionStatus CurrentStatus
        {
            get
            {
                return currentStatus;
            }
            set
            {
                currentStatus = value;
                SetCurrentActionStatus(value);
            }
        }

        private static void SetCurrentActionStatus(RoutineExecutionStatus value)
        {
            if (CurrentAction != null) CurrentAction.CurrentStatus = value;
            if (CurrentAction1120 != null) CurrentAction1120.CurrentStatus = value;
        }

        public static EventLog EventLog { get; set; }
        private static readonly RoutineExecution RoutineExecution = new RoutineExecution();
        private static readonly RoutineExecutionHistory RoutineExecutionHistory = new RoutineExecutionHistory();
        private static DateTime StartedRunDate { get; set; }
        private static int RoutineExecutionId { get; set; }
        private static short Tentatives { get; set; }
        public static bool ProcessRunning { get; set; }
        private static string DllVersion { get; set; }
        private static string DllTempFolder { get; set; }
        private static string DllToExecute { get; set; }
        private static string LibraryPath { get; set; }

        private static string DllFolder
        {
            get
            {
                var dllFolder = ConfigurationManager.AppSettings["DllFolder"];

                if (dllFolder.ToUpper().Contains(Environment.MachineName.ToUpper()))
                {
                    dllFolder = dllFolder.ToLower()
                        .Replace(string.Format(@"\\{0}.lac.nsroot.net\c$\", Environment.MachineName.ToLower()), @"C:\")
                        .Replace(string.Format(@"\\{0}\C$\", Environment.MachineName.ToLower()), @"C:\");
                }

                return dllFolder;
            }
        }

        private static string Proxy { get { return ConfigurationManager.AppSettings["Proxy"]; } }
        private static string StartPath { get { return ConfigurationManager.AppSettings["StartPath"]; } }
        private static string StopPath { get { return ConfigurationManager.AppSettings["StopPath"]; } }
        private static string ExecutionHistoryPath { get { return ConfigurationManager.AppSettings["ExecutionHistoryPath"]; } }
        private static string RunningFile { get { return ConfigurationManager.AppSettings["RunningFile"]; } }
        private static string TempFolder { get { return ConfigurationManager.AppSettings["TempFolder"]; } }
        private static long TimeLogMemory { get { return long.Parse(ConfigurationManager.AppSettings["TimeLogMemory"]); } }
        internal static string NetworkUser { get { return ConfigurationManager.AppSettings["NetworkUser"]; } }
        internal static string NetWorkPassword { get { return ConfigurationManager.AppSettings["NetWorkPassword"]; } }
        private static string WaitingExecutionPath { get { return ConfigurationManager.AppSettings["WaitingExecutionPath"]; } }
        internal static string ServerName { get { return DllFolder.Split(new[] { "/", @"\\", @"\" }, StringSplitOptions.RemoveEmptyEntries).First(); } }
        private static RoutineExecution NextExecution { get; set; }
        public static int MachineId { get; set; }

        internal static string MemoryUsagePath
        {
            get
            {
                var dllFolder = Path.GetDirectoryName(DllFolder);
                return Path.Combine(dllFolder, "MemoryUsage", MachineId.ToString());
            }
        }

        internal static string ErrorLog
        {
            get
            {
                var dllFolder = Path.GetDirectoryName(TempFolder);
                return Path.Combine(dllFolder, "ErrorLog.txt");
            }
        }

        private static string ExecutionLog
        {
            get
            {
                var dllFolder = Path.GetDirectoryName(TempFolder);
                return Path.Combine(dllFolder, "ExecutionLog.txt");
            }
        }

        #endregion

        public static void StartEngine()
        {
            if (ProcessRunning) return;
            var executionHistory = string.Empty;

            try
            {
                ProcessRunning = true;
                Tentatives = 0;
                LogUtil.PathLogErro = ErrorLog;
                if (File.Exists(RunningFile)) File.Delete(RunningFile);

                var dataCurrentLog = File.ReadLines(ExecutionLog).ToList();
                if (dataCurrentLog.Count > 500)
                {
                    dataCurrentLog.RemoveRange(0, dataCurrentLog.Count - 500);
                    File.WriteAllLines(ExecutionLog, dataCurrentLog);
                }

                NextExecution = RoutineExecution.GetWaitingFreeMachineRoutine(MachineId);
                    //.FirstOrDefault(x => !File.Exists(String.Format(ExecutionHistoryPath, x.Id)));

                if (NextExecution == null || NextExecution.LastHistory.Status == (short)RoutineExecutionStatus.InProgress)
                {
                    File.AppendAllLines(ExecutionLog, new[] { string.Format(HistoryDetail.NoExecution, DateTime.Now) });
                    return;
                }

                executionHistory = String.Format(ExecutionHistoryPath, NextExecution.Id);

                //if (NextExecution.Machine == null && new Machine().SelectByRoutineConfigurations(NextExecution.RoutineId).Count() > 1)
                //{
                //    var machineNextExecution = RoutineExecution.GetScheduleSpecificMachine(MachineId);

                //    if (machineNextExecution != null)
                //    {
                //        if (DateTime.Now.AddMinutes(NextExecution.Routine.TotalMinutesExecution) > machineNextExecution.ScheduledDateTime)
                //        {
                //            File.AppendAllLines(ExecutionLog, new[] { string.Format(HistoryDetail.NoEnoughtTimeToRun, NextExecution.Routine.Name, machineNextExecution.Routine.Name) });
                //            return;
                //        }
                //    }
                //}

                RoutineExecutionHistory.DeleteWaitingExecutionFile(NextExecution.Id);
                File.WriteAllText(executionHistory, string.Empty);
                File.WriteAllText(RunningFile, string.Empty);

                CurrentStatus = RoutineExecutionStatus.InProgress;
                UpdateStatus(NextExecution, currentStatus, HistoryDetail.ExecutionStarting);
                File.AppendAllLines(ExecutionLog, new[] { string.Format(HistoryDetail.ExecutingRoutine, NextExecution.Routine.Name, DateTime.Now, NextExecution.Id) });
                RunProcess();
                CurrentStatus = RoutineExecutionStatus.Executed;
            }
            catch (Exception e)
            {
                if (string.IsNullOrWhiteSpace(executionHistory) && File.Exists(executionHistory)) File.Delete(executionHistory);

                CurrentStatus = RoutineExecutionStatus.Error;
                LogUtil.PathLogErro = ErrorLog;
                LogUtil.LogError(EventLog, e);

                if (NextExecution != null)
                {
                    RoutineExecutionHistory.DeleteWaitingExecutionFile(NextExecution.Id);
                    InsertNewTentative(NextExecution);
                }
            }
            finally
            {
                try
                {
                    if (File.Exists(RunningFile)) File.Delete(RunningFile);
                    timerMemory.Stop();

                    SetEndsOn();
                }
                catch { }

                NextExecution = null;
                RoutineExecutionId = 0;
                ProcessRunning = false;
                //AssemblyRunner.ClearRunner();
                //Machine.Status = (int)MachineStatus.Idle;
                //Machine.Save(Machine);
            }
        }

        private static void SetEndsOn()
        {
            if (NextExecution == null) return;

            try
            {
                RoutineExecutionHistory.DeleteWaitingExecutionFile(NextExecution.Id);
                RoutineExecution.UpdateStatus(true, RoutineExecution.SelectById<RoutineExecution>(RoutineExecutionId).RoutineId);
            }
            catch { }

            var i = 0;

            NextExecution.SetEndsOn();
            //NextExecution.EndsOn = DateTime.Now;
            //NextExecution.Save(NextExecution);
            //Thread.Sleep(300);

            //while (!NextExecution.EndsOn.HasValue)
            //{
            //    Thread.Sleep(300);
            //    i++;
            //    NextExecution.EndsOn = DateTime.Now;
            //    NextExecution.Save(NextExecution);

            //    if (i > 70) break;
            //}
        }

        public static void SetStoppedRoutine()
        {
            if (File.Exists(RunningFile)) File.Delete(RunningFile);

            if (NextExecution == null) return;

            CurrentStatus = RoutineExecutionStatus.Stopped;
            UpdateStatus(NextExecution, CurrentStatus, HistoryDetail.SetStoppedByUser);
            SetEndsOn();

            UpdateStatus(NextExecution, CurrentStatus, HistoryDetail.StoppedNewTentative);
            InsertNewTentative(NextExecution);
        }

        private static void TimerMemoryOnElapsed(object sender, ElapsedEventArgs elapsedEventArgs)
        {
            LogMemoryUsage();
        }

        private static void GenerateError(string errorMessage, bool endExecution)
        {
            CurrentStatus = RoutineExecutionStatus.Error;

            try
            {
                LogUtil.PathLogErro = ErrorLog;
                LogUtil.LogError(EventLog, errorMessage);
            }
            catch
            {
            }

            var history = new RoutineErrorHistory
            {
                Date = DateTime.Now,
                Description = "Error is opened and waiting for action.",
                Status = (short)RoutineErrorStatus.Opened,
                UserId = NextExecution.Routine.ResponsibleId,
                RoutineError = new RoutineError
                {
                    ErrorDescription = errorMessage,
                    OcurredOn = DateTime.Now,
                    RoutineExecutionId = NextExecution.Id,
                    RoutineErrorTypeId = 1 //Generated by system
                }
            };

            history.Save(history);

            if (endExecution)
                SetEndsOn();

            UpdateStatus(NextExecution, CurrentStatus, errorMessage);
        }

        private static void UpdateStatus(RoutineExecution execution, RoutineExecutionStatus status, string details = null)
        {
            RoutineExecutionHistory.InsertHistory(execution.Id, status, details);
        }

        private static void RunProcess()
        {
            //Machine.Status = (int)MachineStatus.Running;
            //Machine.Save(Machine);

            RoutineExecutionId = NextExecution.Id;
            string errorMessage;
            //NextExecution.StartsOn = DateTime.Now;
            //NextExecution.MachineId = MachineId;

            if (NextExecution.Tentatives == 0) NextExecution.Tentatives++;

            UpdateStatus(NextExecution, CurrentStatus, HistoryDetail.UpdatingMachineAndStartDate);
            NextExecution.Save(NextExecution);

            //var cont = 0;
            //while (cont < 35 && (!NextExecution.MachineId.HasValue || !NextExecution.StartsOn.HasValue))
            //{
            //    Thread.Sleep(1000);

            //    NextExecution.StartsOn = DateTime.Now;
            //    NextExecution.MachineId = MachineId;

            //    if (NextExecution.Tentatives == 0) NextExecution.Tentatives++;

            //    NextExecution.Save(NextExecution);

            //    cont++;
            //}

            try
            {
                Context.Instance.LoadProperty(NextExecution, x => x.Routine, MergeOption.OverwriteChanges);
                Context.Instance.LoadProperty(NextExecution.Routine, x => x.LibraryVersion, MergeOption.OverwriteChanges);
            }
            catch { }

            UpdateStatus(NextExecution, CurrentStatus,
                string.Format(HistoryDetail.Started, NextExecution.Routine.Name, NextExecution.Routine.LibraryVersion.Version, Environment.MachineName));

            try
            {
                //using (NetworkShareAccesser.Access(ServerName, NetworkUser, NetWorkPassword))
                using (ImpersonateCitiUser.GetImpersonateUser(NetworkUser, NetworkUser, NetWorkPassword))
                {
                    LibraryPath = Path.Combine(DllFolder,
                                                   NextExecution.Routine.LibraryVersion.LibraryId.ToString(),
                                                   ((LibraryType)NextExecution.Routine.LibraryVersion.Type).ToString(),
                                                   NextExecution.Routine.LibraryVersion.Version);

                    CopyDllToTempFolder(LibraryPath, NextExecution);

                    DllToExecute = Path.Combine(DllTempFolder, NextExecution.Routine.LibraryVersion.LibraryFile);

                    UpdateStatus(NextExecution, CurrentStatus, string.Format(HistoryDetail.ReadingDllPath, NextExecution.Routine.Name, DllToExecute));

                    if (!File.Exists(DllToExecute))
                    {
                        errorMessage = string.Format(HistoryDetail.DllNotFound, NextExecution.Routine.Name, DllToExecute);
                        GenerateError(errorMessage, true);
                        return;
                    }

                    DllVersion = AssemblyRunner.ValidateDll(DllToExecute, NextExecution.Routine.Class);
                    UpdateStatus(NextExecution, CurrentStatus, HistoryDetail.DllLoaded);

                    Run(NextExecution);
                }
            }
            catch (Exception e)
            {
                //errorMessage = string.Format(ErrorDetail.Error, string.Concat(e.Message, e.InnerException != null ?
                //    string.Concat("Inner exception: ", e.InnerException.Message) : string.Empty, " Stack Trace: ", e.StackTrace));
                errorMessage = GetDetailedError(HistoryDetail.Error, NextExecution, e);
                GenerateError(errorMessage, true);
            }
            finally
            {
                DropTempFiles(NextExecution);
            }
        }

        private static void DropTempFiles(RoutineExecution execution)
        {
            try
            {
                Context.Instance.LoadProperty(execution, x => x.RoutineExecutionHistories, MergeOption.OverwriteChanges);
                Context.Instance.Refresh(RefreshMode.StoreWins, execution);
            }
            catch
            {

            }
            //var lastStatus = execution.RoutineExecutionHistories.Any()
            //    ? (RoutineExecutionStatus)execution.LastHistory.Status
            //    : RoutineExecutionStatus.Error;
            try
            {
                UpdateStatus(execution, CurrentStatus, HistoryDetail.DroppingTempFiles);

                var dirInfo = new DirectoryInfo(TempFolder);
                var directories = dirInfo.GetDirectories();

                foreach (var directory in directories)
                {
                    try
                    {
                        Directory.Delete(directory.FullName, true);
                    }
                    catch { }
                }

                UpdateStatus(execution, CurrentStatus, HistoryDetail.TempFilesDropped);
            }
            catch (Exception e)
            {
                UpdateStatus(execution, CurrentStatus, string.Format(HistoryDetail.ErrorOnDropTempFiles, e.Message));
            }
        }

        private static void CopyDllToTempFolder(string libraryPath, RoutineExecution execution)
        {
            UpdateStatus(execution, CurrentStatus, HistoryDetail.CopingFilesToTempFolder);

            DllTempFolder = Path.Combine(TempFolder, FileHelper.MakeValidFileName(string.Concat((execution.Routine.Name.Length > 235
                ? execution.Routine.Name.Substring(0, 235)
                : execution.Routine.Name), DateTime.Now.ToString("yyyyMMdd HHmmss"))));

            if (!Directory.Exists(DllTempFolder))
                Directory.CreateDirectory(DllTempFolder);

            var dirInfo = new DirectoryInfo(libraryPath);
            var files = dirInfo.GetFiles();

            foreach (var tempfile in files)
                tempfile.CopyTo(Path.Combine(DllTempFolder, tempfile.Name));

            Task.WaitAll();

            UpdateStatus(execution, CurrentStatus, HistoryDetail.FilesCopiedToTempFolder);
        }

        private static void Run(RoutineExecution execution)
        {
            //var executable = Activator.CreateInstance(executionClass);

            Tentatives++;

            try
            {
                ExecuteAction(execution);

                InsertSuccessEmail(execution);
            }
            catch (Exception e)
            {
                HandleError(execution, e);
            }

            Tentatives = 0;
        }

        private static void InsertSuccessEmail(Domain.RoutineExecution execution)
        {
            try
            {
                using (var client = new EmailClient())
                {
                    var users = string.Join(";", execution.Routine.Escalations.Where(x => x.Minutes <= 60).Select(x => x.AllUsers))
                        .Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Distinct();

                    var email = new EmailSenderWcf.Email
                    {
                        TemplateId = 982,
                        Importance = EnumsEmailImportance.Normal,
                        To = users.Select(x => new EmailSenderWcf.EmailAddress { Description = x }).ToList(),
                        Parameters = new Dictionary<string, string> 
                        { 
                            { "[RoutineName]", execution.Routine.Name}, 
                            { "[RoutineExecutionId]", execution.Id.ToString() } 
                        }
                    };

                    client.InsertEmailInQueue(email);
                }
            }
            catch
            {
            }
        }

        private static void HandleError(RoutineExecution execution, Exception e)
        {
            CurrentStatus = RoutineExecutionStatus.Error;

            var errorMessage = GetDetailedError(HistoryDetail.ErrorRoutine, execution, e);
            SetEndsOn();

            LogError(errorMessage);
        }

        private static void LogError(string errorMessage)
        {
            CurrentStatus = RoutineExecutionStatus.Error;
            //UpdateStatus(execution, RoutineExecutionStatus.Error, errorMessage);
            GenerateError(errorMessage, true);

            if (NextExecution == null) return;
            Rollback(NextExecution);

            InsertNewTentative(NextExecution);
        }

        public static void InsertNewTentative(RoutineExecution execution)
        {
            try
            {
                RoutineExecution.InsertNewTentative(execution, CurrentStatus);   
            }
            catch (Exception e)
            {
                LogUtil.PathLogErro = ErrorLog;
                LogUtil.LogError(EventLog, new Exception("Inserting new tentative", e));
            }
        }

        private static string GetDetailedError(string historyDetail, RoutineExecution execution, Exception e)
        {
            var errorDescriptionMessage = LogUtil.GetAllExceptionDetails(e);

            return string.Format(historyDetail, execution.Routine.Name, errorDescriptionMessage);
        }

        private static void LogMemoryUsage()
        {
            try
            {
                using (NetworkShareAccesser.Access(ServerName, NetworkUser, NetWorkPassword))
                {
                    var usagePath = Path.Combine(MemoryUsagePath, string.Concat(RoutineExecutionId, ".xml"));

                    if (!File.Exists(usagePath))
                        StartedRunDate = DateTime.Now;

                    var data = File.Exists(usagePath)
                        ? XmlHelper.DeserializeFromXml<List<MemoryUsage>>(usagePath)
                        : new List<MemoryUsage>();

                    var memoryUsage = new MemoryUsage
                    {
                        Seconds = Convert.ToInt32((DateTime.Now - StartedRunDate).TotalSeconds),
                        Size = Process.GetCurrentProcess().PrivateMemorySize64 / 1000
                    };

                    data.Add(memoryUsage);
                    XmlHelper.SerializeToXml(data, usagePath);
                }
            }
            catch
            {

            }
        }

        private static void ExecuteAction(RoutineExecution execution)
        {
            LogMemoryUsage();
            timerMemory.Elapsed += TimerMemoryOnElapsed;
            timerMemory.Start();
            var tokenSource = new CancellationTokenSource();
            var token = tokenSource.Token;
            var timeOut = execution.Routine.EstimatedTime * 600 * execution.Routine.PercentageAcceptableVariation +
                          execution.Routine.EstimatedTime * 60000;

            UpdateStatus(execution, CurrentStatus, string.Format(HistoryDetail.StartExternalCode, execution.Routine.Name));
            UpdateStatus(execution, CurrentStatus, string.Format(HistoryDetail.TimeoutInformation, timeOut / 1000));

            try
            {
                var task = Task.Factory.StartNew(() => ExecuteVersion(execution), token);

                if (!task.Wait(timeOut, token))
                {
                    var errorMessage = string.Format(HistoryDetail.Timeout, execution.Routine.EstimatedTime,
                        execution.Routine.PercentageAcceptableVariation);

                    LogError(errorMessage);
                }
                else
                {
                    CurrentStatus = RoutineExecutionStatus.Executed;
                    UpdateStatus(execution, CurrentStatus, HistoryDetail.ExecutionFinished);
                }

                if (task.Exception != null)
                    throw task.Exception.InnerException ?? task.Exception;
            }
            catch (Exception e)
            {
                throw e.InnerException != null && e.InnerException.InnerException != null
                            ? e.InnerException.InnerException
                            : e.InnerException ?? e;
            }

            //execution.EndsOn = DateTime.Now;
            //execution.Save(execution);
            execution.SetEndsOn();
            LogMemoryUsage();
        }

        private static AssemblyRunner CurrentAssemblyRunner { get { return AssemblyRunner.Runner; } }

        private static void ExecuteVersion(RoutineExecution execution)
        {
            try
            {
                var parameters = new List<object>();
                var schedulerParameters = GetSchedulerParameters(execution);

                CurrentAction = new CurrentAction(execution);
                CurrentAction1120 = new CurrentAction1120(execution);
                CurrentStatus = RoutineExecutionStatus.InProgress;

                switch (DllVersion)
                {
                    case "1.0.0.0":

                        //CurrentAction.CurrentStatus = CurrentStatus;
                        parameters.Add(execution.ScheduledDateTime);
                        parameters.Add(CurrentAction);
                        break;
                    case "1.1.0.0":
                        //CurrentAction = new CurrentAction(execution);
                        //CurrentAction.CurrentStatus = CurrentStatus;
                        parameters.Add(execution.ScheduledDateTime);
                        parameters.Add(CurrentAction);
                        parameters.Add(schedulerParameters);
                        break;
                    case "1.1.2.0":
                        parameters.Add(execution.ScheduledDateTime);

                        //CurrentAction1120.CurrentStatus = CurrentStatus;
                        parameters.Add(CurrentAction1120);
                        parameters.Add(schedulerParameters);

                        break;
                }

                UpdateStatus(execution, CurrentStatus, string.Format(HistoryDetail.RoutineBaseVersion, execution.Routine.Name, DllVersion));

                try
                {
                    using (ImpersonateCitiUser.GetImpersonateUser(execution.Routine.User.Soeid, NetworkUser, NetWorkPassword))
                    {
                        UpdateStatus(execution, CurrentStatus, string.Format(HistoryDetail.RoutineExecuteUser, execution.Routine.User.Soeid));
                        AssemblyRunner.LoadDllAndExecuteMethod(DllToExecute, execution.Routine.Class, "Start", parameters.ToArray());
                    }
                }
                catch (Exception e)
                {
                    if (e.Message.ToUpper().Contains(".PWD"))
                    {
                        UpdateStatus(execution, CurrentStatus, string.Format(HistoryDetail.RoutineExecuteUser, "Local System"));
                        AssemblyRunner.LoadDllAndExecuteMethod(DllToExecute, execution.Routine.Class, "Start", parameters.ToArray());
                    }
                    else
                        throw e;
                }
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        private static Dictionary<string, object> GetSchedulerParameters(RoutineExecution execution)
        {
            Context.SetOverwriteChanges(Context.Instance.Routines);
            Context.Instance.LoadProperty(execution, x => x.Routine, MergeOption.OverwriteChanges);
            var routine = execution.Routine;

            var schedulerParameters = new Dictionary<string, object>
                {
                    {"RobotUsername", NetworkUser},
                    {"RobotPassword", NetWorkPassword},
                    {"Version", routine.LibraryVersion.Version},
                    {"Proxy", Proxy},
                    {"ExecutionPath", LibraryPath},
                    {"RoutineExecutionId", execution.Id},
                    {"StartPath", StartPath},
                    {"StopPath", StopPath},
                    {"SoeidResponsible", routine.User.Soeid}
                };

            Context.SetOverwriteChanges(Context.Instance.RoutineParameters);

            try
            {
                Context.Instance.LoadProperty(routine, x => x.RoutineParameters, MergeOption.OverwriteChanges);
            }
            catch { }

            var routineParameters = routine.RoutineParameters.ToList().Select(x => new KeyValuePair<string, object>(x.Name, RoutineParameter.FillVariables(x.Value)));

            foreach (var routineParameter in routineParameters)
            {
                UpdateStatus(execution, CurrentStatus, string.Format("Parameter name: '{0}'. Value: '{1}'", routineParameter.Key, routineParameter.Value.ToString()));
                schedulerParameters.Add(routineParameter.Key, routineParameter.Value);
            }

            return schedulerParameters;
        }

        private static void Rollback(RoutineExecution execution)
        {
            CurrentStatus = RoutineExecutionStatus.Error;
            UpdateStatus(execution, CurrentStatus, HistoryDetail.RollingBack);

            try
            {
                var parameters = new List<object>();
                var dllVersionNumber = int.Parse(DllVersion.Replace(".", string.Empty));

                if (dllVersionNumber < 1120)
                {
                    //CurrentAction = new CurrentAction(execution);
                    //CurrentAction.CurrentStatus = CurrentStatus;
                    parameters.Add(CurrentAction);
                }
                else
                {
                    StopLogAction();
                    //CurrentAction1120 = new CurrentAction1120(execution);
                    //CurrentAction1120.CurrentStatus = CurrentStatus;
                    parameters.Add(CurrentAction1120);
                    parameters.Add(GetSchedulerParameters(execution));
                }

                CurrentAssemblyRunner.ExecuteMethod(DllToExecute, execution.Routine.Class, "Rollback", parameters.ToArray());
            }
            catch (Exception e)
            {
                var errorMessage = GetDetailedError(HistoryDetail.RolledBackError, execution, e);
                UpdateStatus(execution, CurrentStatus, errorMessage);
            }

            UpdateStatus(execution, CurrentStatus, HistoryDetail.RolledBack);
        }

        private static void StopLogAction()
        {
            if (CurrentAction1120 != null) CurrentAction1120.StopLog();
        }
    }
}
